<?php
/***
 * Candy框架 App类
 * 
 * $Author: 刘森 (fingerboy@qq.com) $
 * $Date: 2019-08-01 23:00:09 $   
 */

declare(strict_types=1);
namespace Candy\Core;

defined('CANDY') OR die('You Are A Bad Guy. o_O???');

final Class App extends Container
{
	/**
     * 初始化
     * @var bool
     */
    protected $initialized = false;
	
	//构造函数
	public function __construct(){}
	
	/**
     * 初始化函数
     */
	public static function run(): void
	{	
		//重置debug信息
		if(defined('ONCE') && isDebug()){
			Debug::reload();
		}
		
		//启动中间件
		Security::run();
		
		//初始化
		self::initialize();
		
		//开始运存保存
		C('startMemory', memory_get_usage());
		
		//黑名单检测
		if(isDebug() === false){
			if(Security::check()){
				showTplMsg('shutdown', '因非法操作您已经被禁止访问，请联系管理员！', null, null, true);
			}
		}
		
		//运行初始化中间件
		Security::runMiddlewares();
		
		//解析数据库配置
		self::dbConfig();

		//开启session
		self::sessionLoading();

		//cli模式下
		if(defined('CLIWORKING'))
			$_SESSION = session();


		//运行获取参数前中间件
		Security::runMiddlewares('Before');

		//解析处理URL
		Prourl::parseUrl();

		//初始化
		if(fileExistsCase(INCPATH . 'Init.inc.php'))
			include INCPATH . 'Init.inc.php';

		//系统基本配置
		if(fileExistsCase(INCPATH . 'System.inc.php'))
			include INCPATH . 'System.inc.php';

		//debug模式
		(defined('DEBUG') && DEBUG == 1) && $GLOBALS['debug'] = 1;

		//声明引用类库的地址库
		isset($specialclass) OR $specialclass = loadConfig('Specialclass');
		if(!empty($specialclass)){
			G('specialClass',$specialClass);
		}

		//初始化操作
		$initProurl = pathinfo(basename($_SERVER['DOCUMENT_URI']))['filename'] . 'InitProurl';
		if(G($initProurl) != null){
			C(['APP'=>null, 'CONTROL'=>null, 'ACTION'=>null]);
			$initProurl = G($initProurl);
			isset($initProurl['app']) && C('APP', $initProurl['app']);
			isset($initProurl['control']) && C('CONTROL', $initProurl['control']);
			isset($initProurl['action']) && C('ACTION', $initProurl['action']);
		}

		//定义模板后缀
		isset($separate) OR $separate = '/';

		//定义模板后缀
		isset($tplprefix) OR $tplprefix = '.html';

		//保存
		G(['SEPARATE'=>$separate, 'TPLPREFIX'=>$tplprefix]);

		//默认模板目录
		$tplstyle = C('TPLSTYLE');
		is_null($tplstyle) && $tplstyle = 'default';

		//插件模式
		$addons = isset($addons) ?? false;

		//保存
		C(['APP_TPL_PATH'=>$tplpath, 'TPLSTYLE'=>$tplstyle, 'Addons'=>$addons]);

		//Debug模式进入APP初始创建
		if(isDebug() && ((isset($_GET['add']) && in_array($_GET['add'], ['', 'addon', 'plug'])) || fileExistsCase(RUNTIME.'init.lock') === false)){
			Build::start();
		}

		//初始化类
		self::loading();

		//项目公共语言库
		$LANG = [];
		$lg = G('LANG');
		$clangfile = C('APP_PATH') .'Languages/'. $lg .'/Common.lang.php';
		if(fileExistsCase($clangfile))
			include $clangfile;

		//操作语言库
		$langfile = C('APP_PATH') .'Languages/'. $lg .'/'. ucfirst(strtolower($_GET['m'])).'.lang.php';
		if(fileExistsCase($langfile))
			include $langfile;

		//插件语言库
		$plangfile = PLUGPATH . C('RAPPNAME') . '/Languages/'. $lg .'/'. ucfirst(strtolower($_GET['m'])).'.lang.php';
		if(fileExistsCase($plangfile)){
			include $plangfile;
			$plangfile = $langfile;
		}
		Debug::addMsg('[<b>Languages file</b>] 当前项目语言库路径：'. str_replace(CANDYROOT, '/', $langfile), 3);
		
		//储存语言
		C('LANGINFO', $LANG);

		//实例化操作对象
		self::doRun();
	}
	
	/**
     * 初始化
     */
    public static function initialize()
    {
        //非Cli模式下读取G用于跨域
		if(defined('CLIWORKING') === false){
			$frameVariableForG = F('frameVariableForG');
			if(!empty($frameVariableForG)){
				S('g', $frameVariableForG, '', null, true);
				C('frameVariableForG', $frameVariableForG);
			}
		}
		
		//1%的几率清除过期缓存
		if(mt_rand(1, 100) > 99){
			$cache = \Candy\Extend\Cache\CacheServer::instance();
			if(explode('\\', $cache::class)[4] == 'File'){
				$cache->autoDeleteExpiredFile();
				Debug::addMsg('<font color=\'red\'>自动清理F函数缓存的过期变量!</font>');
			}
		}
		
		if(defined('INIT')){}else{
			//注册数据流操作
			stream_wrapper_register('code', 'Candy\Core\Stream');
			
			//包含项目中的函数库文件
			$funcList = glob(SOURCEPATH .'Func/*.func.php');
			foreach ($funcList as $funcPath)
			{
				requireCache($funcPath);
			}
			
			define('INIT', true);
		}
		
		//PHP版本检测
		if(version_compare(PHP_VERSION,'8.0', '<=')){
			showTplMsg('shutdown', 'PHP版本不能低于8.0', null, null, true);
		}
    }

    /**
     * 是否初始化过
     * @return bool
     */
    public function initialized()
    {
        return $this->initialized;
    }
	
	/**
     * 解析数据库配置
     */
	protected static function dbConfig(): void
	{
		//包含数据配置文件
		isset($config) OR $config = loadConfig('Config');

		if(!empty($config)){
			//cache配置
			if(isset($config['Servers']['open']) && $config['Servers']['open'] == true){
				$svtype = $config['Servers']['type'] ?? 'Memcache';
				G('cacheDriver',['type'=>$svtype,'confing'=>$config['Servers']['confing']]);
			}else{
				$svtype = '';
			}
			unset($config['Servers']);

			//开启缓存
			isset($config['CSTART']) OR $config['CSTART'] = 0;
			$memCache = cacheLoading($config['CSTART'], $svtype);

			//语言库
			G('LANG', 'zh-cn');
			isset($config['LANG']) && G('LANG', $config['LANG']);
			
			//数据库配置剔除
			$dbconfig = $config['DB'];
			unset($config['DB']);
			
			//扩展配置
			G($config);
			
			//默认数据库
			$db = $dbconfig['default'];

			//当前域名的数据库
			if(isset($dbconfig[$_SERVER['HTTP_HOST']])){
				$db = $dbconfig[$_SERVER['HTTP_HOST']];
			}

			//当前项目的数据库
			if(isset($dbconfig[C('APP')])){
				$db = $dbconfig[C('APP')];
			}

			//当前控制器的数据库
			if(isset($dbconfig[C('CONTROL')])){
				$db = $dbconfig[C('CONTROL')];
			}

			//当前操作的数据库
			if(isset($dbconfig[C('ACTION')])){
				$db = $dbconfig[C('ACTION')];
			}

			//设置
			C($db);
		}
	}
	
	/**
	 * 开启缓存
	 */
	protected static function sessionLoading():void
	{
		//补充SESSID
		$sessionid = null;
		if(isset($_REQUEST['sessionid'])){
			if(isset($_GET['sessionid'])){
				$sessionid = $_GET['sessionid'];
				unset($_GET['sessionid']);
			}else{
				$sessionid = $_POST['sessionid'];
				unset($_POST['sessionid']);
			}
		}
		
		//如果Memcach开启，设置将Session信息保存在Memcache服务器中
		$cache = \Candy\Extend\Cache\CacheServer::instance();
		$memName = explode('\\', $cache::class)[4];
		if(defined('CLIWORKING') === false && $memName != 'File'){
			\Candy\Extend\Cache\CacheSession::start($cache->getMem(), $sessionid);
			Debug::addMsg('开启会话Session (使用Memcache保存会话信息)'); //debug
		}else{
			if(defined('CLIWORKING')){
				if($memName != 'File'){
					\Workerman\Protocols\Http\Session::handlerClass('', $cache);
				}
				
				//开启session
				Container::getInstance()->get('Request')->session($sessionid);
			}else{
				if(!is_null($sessionid)){
					session_id($sessionid);
				}
				session_start();
				Debug::addMsg('<font color=\'red\'>开启会话Session </font>(但没有使用Memcache，开启Memcache后自动使用)');
			}
		}
	}
	
	/**
     * 初始化函数
     */
	public static function loading(): void
	{
		//目录获取
		$rootpath = preg_replace("/[\/\\\\]{1,}/", '/', getcwd() .'/');
		$GLOBALS['root'] = $lang_path = str_replace(CANDYROOT, '/', $rootpath);
		$c_root = rtrim($GLOBALS['root'], '/');
		$c_addon = $c_root .'/Addons/';
		G(['ROOTPATH'=>$rootpath, 'C_ROOT'=>$c_root, 'c_addon'=>$c_addon]);
		$candy_path = rtrim(str_replace(CANDYROOT, '/', CANDYPATH), '/');
		
		//系统一些标注
		Debug::addMsg('[<b>Candy</b>] 框架所在位置：'. $candy_path, 3);
		
		if(!defined('CLIWORKING')){
			$scriptname = ltrim($_SERVER['SCRIPT_NAME'], '/');
			Debug::addMsg('[<b>Main file</b>] 入口文件位置：'. $scriptname , 3);
		}
		
		//项目的全局资源目录
		$c_public = G('C_PUBLIC');
		if(is_null($c_public)){
			$GLOBALS['public'] = $GLOBALS['root'] . 'Public/';
			$c_public = rtrim($GLOBALS['public'], '/');
			Debug::addMsg('[<b>Public</b>] 公共资源请求位置（默认）：'. $c_public, 3);
		} else {
			Debug::addMsg('[<b>Public</b>] 公共资源请求位置：'. $c_public, 3);
		}
		
		//初始化模版路径
		initTplPath();
		
		//和上传有关的默认选项的设置
		$c_up_path = G('C_UP_PATH');
		if(is_null($c_up_path)){
			$c_up_path = CANDYROOT.'Public/uploads';
			Debug::addMsg('[<b>Upload path</b>] 上传的资源请求位置（默认）：'. str_replace(CANDYROOT, '/', $c_up_path) , 3);
		}else {
			Debug::addMsg('[<b>Upload path</b>] 上传的资源请求位置：'. str_replace(CANDYROOT, '/', $c_up_path) , 3);
		}
		$c_upcw_path = G('C_UPCW_PATH');
		if(is_null($c_upcw_path)){
			$c_upcw_path = CANDYROOT .'Public/thumbs';
			Debug::addMsg('[<b>Thumb path</b>] 图片缓存请求的位置(默认)：'. str_replace(CANDYROOT, '/', $c_upcw_path), 3);
		}else{
			Debug::addMsg('[<b>Thumb path</b>] 图片缓存请求的位置：'. str_replace(CANDYROOT, '/', $c_upcw_path), 3);
		}

		//判断是否设置过runtime的路径
		if(defined('C_RUN_PATH')){
			Debug::addMsg('[<b>Runtime</b>] 运行时生成的缓存runtime目录位置：'. C_RUN_PATH, 3);
		}else{
			Debug::addMsg('[<b>Runtime</b>] 运行时生成的缓存runtime目录位置(默认)：'. str_replace(CANDYROOT, '/', RUNTIME), 3);
		}
		
		//保存
		G(['C_PUBLIC'=>$c_public, 'C_UP_PATH'=>$c_up_path, 'C_UPCW_PATH'=>$c_upcw_path]);
	}
	
	/**
	 *框架启动入口
	 */
	public static function doRun(): void
	{
		//标准class名称
		$getM = ucfirst(strtolower($_GET['m']));
		
		//插件模式
		$isAddon = is_null(C('ISADDON')) ? false : true;
		
		//获取最终的类名和目录
		$classInfo = self::getClassInfo($getM, $isAddon);
		
		//控制器类所在的路径
		$srccontrolerfile = C('APP_PATH') .'Controls/'. $getM .'.class.php';
		
		$scfile = str_replace(CANDYROOT, '/', $srccontrolerfile);
		Debug::addMsg("当前控制器类的路径: <b>$scfile</b> 文件！", 6);
		
		//公共类创建
		self::commonControler(C('APP_PATH').'Controls/', $classInfo['path']);
		if(empty($classInfo['extendName'])){
			//控制器类创建
			$working = empty($classInfo['extend']) ? self::controler($srccontrolerfile, $classInfo['path'], $getM) : true;
			$className = $classInfo['className'];
		}else{
			$working = self::controler($srccontrolerfile, $classInfo['path'], $getM);
			$className = $classInfo['extendName'];
		}
		
		//debug模式下不缓存
		if(isDebug()){
			headerLoading('Cache-Control: no-cache,must-revalidate');
			headerLoading('Pragma: no-cache');
			headerLoading("Expires: -1");
		}
		
		//创建控制器
		if($working === true){
			$objName = C('APPNAME') . C('CONTROL');
			$objWorker = Container::getInstance()->get($objName) ?? Container::getInstance()->bind($objName, N($className))->get($objName);
			$objWorker->working();
		}else{
			N('Action')->working();
		}
	}
	
	/**
	 * 父类控制器的生成
	 *
	 * @param	string	$srccontrolerpath	原基类控制器的路径
	 * @param	string	$controlerpath		目标基类控制器的路径
	 */ 
	public static function commonControler(string $srccontrolerpath,string $controlerpath,string $appName = ''): void
	{
		empty($appName) && $appName = C('APPNAME');
		$srccommon = $srccontrolerpath. 'Common.class.php';
		$common = $controlerpath . '/common.class.php';
		
		//不存在的项目
		if(is_dir($srccontrolerpath)){
			//生成目录
			is_dir($controlerpath) OR \Candy\Extend\Dir::create($controlerpath);
			
			//不存在不编译
			if(fileExistsCase($srccommon)){
				//如果新控制器不存在， 或原控制器有修改就重新生成
				if(!fileExistsCase($common) || filemtime($srccommon) > filemtime($common)){
					$commonContent = fileGetContents($srccommon);
					$commonContent=preg_replace('/class\s+(.+?)\s+extends\s+(.+?)\s*{/i','class \1 extends \2 {',$commonContent,1);
					
					preg_match('/extends\s+(.+?)\s*{/i', $commonContent, $extends);
					if(trim($extends[1]) == 'Base'){
						$commonContent = preg_replace('/'.trim($extends[0]).'/', 'extends \Candy\APP\Common\Base {', $commonContent, 1);
					}
					
					//编译插件
					$commonContent = preg_replace_callback('#\t*\/\/\s*hook\s+([^\s]+)#is', 'Candy\Core\Hook::processHookCallback', $commonContent);
					filePutContents($common,$commonContent);
				}
			}else{
				if(!fileExistsCase($common)){
					$commonContent = str_replace('{APPNAME}', $appName, base64_decode('PD9waHAKbmFtZXNwYWNlIEFQUFxDb250cm9sXHtBUFBOQU1FfTsKZGVmaW5lZCgnQ0FORFknKSBPUiBkaWUoJ1lvdSBBcmUgQSBCYWQgR3V5LiBvX08/Pz8nKTsKCmNsYXNzIENvbW1vbiBleHRlbmRzIFxBUFBcQ29tbW9uXEJhc2UgewoJZnVuY3Rpb24gaW5pdCgpewoKCX0JCn0='));
					filePutContents($common,$commonContent);
				}
			}
			clearstatcache();
		}
	}
	
	/**
	 * 控制器的生成
	 *
	 * @param	string	$srccontrolerfile	原基类控制器的路径
	 * @param	string	$controlerpath		目标基类控制器的路径
	 * @param	string	$m					控制器名称
	 * @param	string	$appName			项目名称
	 */ 
	public static function controler(string $srccontrolerfile,string $controlerpath,string $m,string $appName = ''): bool
	{
		empty($appName) && $appName = C('APPNAME');
		$controlerfile = $controlerpath.'/'.strtolower($m).'action.class.php';
		if(!fileExistsCase($srccontrolerfile)){
			if(fileExistsCase($controlerfile) ){
				return true;
			}else{
				Debug::addMsg('<font color=\'red\'>模块不存在,应在'. str_replace(CANDYROOT, '/', $srccontrolerfile) .'文件，声明一个类名为'. $m .'的类！</font>');
				is_null(C('S404')) && C('S404', true);
				return false;
			}
		}
		
		//如果新控制器不存在或原控制器有修改就重新生成
		if(!fileExistsCase($controlerfile) || filemtime($srccontrolerfile) > filemtime($controlerfile)){
			//将控制器类中的内容读出来
			$classContent=fileGetContents($srccontrolerfile);	
			//看类中有没有继承父类
			$super='/extends\s+(.+?)\s*{/i'; 
			//如果已经有父类
			if(preg_match($super,$classContent, $arr)){
				$classContent=preg_replace('/class\s+(.+?)\s+extends\s+(.+?)\s*{/i','class \1Action extends \2 {',$classContent,1);
				
				preg_match('/extends\s+(.+?)\s*{/i', $classContent, $extends);
				if(trim($extends[1]) == 'Base'){
					$classContent = preg_replace('/'.trim($extends[0]).'/', 'extends \Candy\APP\Common\Base {', $classContent, 1);
				}
				
				//编译插件
				$classContent = preg_replace_callback('#\t*\/\/\s*hook\s+([^\s]+)#is', 'Candy\Core\Hook::processHookCallback', $classContent);
				//新生成控制器类
				filePutContents($controlerfile, $classContent);
			//没有父类时
			}else{ 
				//继承父类Common
				$classContent=preg_replace('/class\s+(.+?)\s*{/i','class \1Action extends Common {',$classContent,1);
				
				//编译插件
				$classContent = preg_replace_callback('#\t*\/\/\s*hook\s+([^\s]+)#is', 'Candy\Core\Hook::processHookCallback', $classContent);
				//生成控制器类
				filePutContents($controlerfile,$classContent);
			}
			clearstatcache();
		}
		
		return true;
	}
	
	/**
	 * Model的生成
	 *
	 * @param	string	$className	Model名称
	 * @param	string	$app		APP名称
	 */ 
	public static function model(string $className,string $app = ''): string
	{
		$appName = C('APPNAME');
		$appPath = C('APP_PATH');
		$driver = 'Candy\\Extend\\DB\\Driver\\' . ucfirst(strtolower(G('DRIVER')));
		$className = ucfirst($className);
		if(empty($driver)){
			Debug::showMessage('请设置数据库引擎 Pdo 或 Mysqli ！', 'Mysql');
		}
		//创建目录
		if(is_null(C('ISADDON'))){
			$path = RUNTIME.'Models/'. $appName .'/';
		}else{
			$path = RUNTIME.'Models/Addons/'. $appName .'/';
		}
		
		$src = '';
		if(empty($app)){
			//判断项目是否存在
			if(is_dir($appPath .'Models/')){
				$src = $appPath .'Models/'. $className .'.class.php';
				$psrc = $appPath .'Models/___.class.php';
				$className = $className;
				$parentClass = '___model';
				$to = $path.strtolower($className).'model.class.php';
				$pto = $path.$parentClass.'.class.php';
			}
		}else{
			if(is_dir(CANDYROOT.'Application/'.$app.'/Models/')){
				$src = CANDYROOT.'Application/'.$app.'/Models/'. $className .'.class.php';
				$psrc = CANDYROOT.'Application/'.$app.'/Models/___.class.php';
				$className = ucfirst($app).$className;
				$parentClass = ucfirst($app).'___model';
				$to = $path.strtolower($className).'model.class.php';
				$pto = $path.$parentClass.'.class.php';
			}
		}
		
		//扩展类
		$m = ucfirst(strtolower($_GET['m']));
		$extendkey = 'extendpath.' . C('RAPPNAME') . $m;
		$extendinfo = C($extendkey);
		$extsrc = empty($extendinfo) ? PLUGPATH . C('RAPPNAME') .'/Models/'. $className .'.class.php' : $extendinfo['path'] .'/Models/'. ($extendinfo['path'] == PLUGPATH . C('RAPPNAME') ? '' : C('RAPPNAME') . '/') . $className .'.class.php';
		
		if(fileExistsCase($extsrc)){
			$super='/extends\s+(.+?)\s*{/i'; 
			$extClassContent = fileGetContents($extsrc);
			$extend = false;
			if(preg_match($super,$extClassContent, $tarr)){
				$className = $className . 'Extend';
				$extend = true;
			}else{
				$className = $className . 'Model';
			}
			
			$farth = false;
			$classContent = fileGetContents($src);
			if(preg_match($super,$classContent, $arr)){
				$psrc = str_replace('___', $arr[1], $psrc);
				$pto = str_replace('___', strtolower($arr[1]), $pto);
				if(fileExistsCase($pto)){
					includeCache($pto);
				}else{
					$farth = true;
				}
			}
			
			if(!fileExistsCase($to) || filemtime($extsrc) > filemtime($to) || filemtime($src) > filemtime($to)){
				\Candy\Extend\Dir::create($path);
				//如果已经有父类
				if($extend && fileExistsCase($src)){
					//扩展内容
					$extClassContent = preg_replace('/class\s+(.+?)\s+extends\s+(.+?)\s*{/i','class \1Extend extends \2Model {',$extClassContent,1);
					//如果已经有父类
					if($farth){
						if(fileExistsCase($psrc)){
							if(!fileExistsCase($pto) || filemtime($psrc) > filemtime($pto)){
								$pclassContent=fileGetContents($psrc);
								$pclassContent=preg_replace('/class\s+(.+?)\s*{/i','class '.$arr[1].'Model extends '.$driver.' {',$pclassContent,1);
								//编译插件
								$pclassContent = preg_replace_callback('#\t*\/\/\s*hook\s+([^\s]+)#is', 'Candy\Core\Hook::processHookCallback', $pclassContent);
								filePutContents($pto, $pclassContent);
							}
						}else{
							showTplMsg('shutdown', '<font color=\'red\'>文件'.$psrc.'不存在!</font>');
						} 
						$driver = $arr[1].'Model';
						clearstatcache();
						includeCache($pto);
						$classContent = preg_replace('/class\s+(.+?)\s+extends\s+(.+?)\s*{/i','class \1Model extends '. $driver .' {',$classContent,1);
					}else{
						$classContent = preg_replace('/class\s+(.+?)\s*{/i','class \1Model extends '.$driver.' {',$classContent,1);
					}
					$classContent = str_replace('?>', '', $classContent) . PHP_EOL . PHP_EOL . str_replace('<?php', '', $extClassContent);
					
				}else{
					if($extend){
						showTplMsg('shutdown', '<font color=\'red\'>文件{$src}不存在!</font>');
					}
					$classContent = preg_replace('/class\s+(.+?)\s*{/i','class \1Model extends '.$driver.' {',$extClassContent,1);
				}
				//编译插件
				$classContent = preg_replace_callback('#\t*\/\/\s*hook\s+([^\s]+)#is', 'Candy\Core\Hook::processHookCallback', $classContent);
				//生成model
				filePutContents($to,$classContent);
			}
		}else{
			if(fileExistsCase($src)){	
				//创建目录
				\Candy\Extend\Dir::create($path);
			
				$classContent=fileGetContents($src);
				$super='/extends\s+(.+?)\s*{/i'; 
				//如果已经有父类
				if(preg_match($super,$classContent, $arr)){
					$psrc=str_replace('___', $arr[1], $psrc);
					$pto=str_replace('___', strtolower($arr[1]), $pto);
					
					if(fileExistsCase($psrc)){
						if(!fileExistsCase($pto) || filemtime($psrc) > filemtime($pto)){
							$pclassContent=fileGetContents($psrc);
							$pclassContent=preg_replace('/class\s+(.+?)\s*{/i','class '.$arr[1].'Model extends '.$driver.' {',$pclassContent,1);
							//编译插件
							$pclassContent = preg_replace_callback('#\t*\/\/\s*hook\s+([^\s]+)#is', 'Candy\Core\Hook::processHookCallback', $pclassContent);
							filePutContents($pto, $pclassContent);
						}
					}else{
						Debug::addMsg('<font color=\'red\'>文件'.$psrc.'不存在!</font>', 4);
					} 
					$driver=$arr[1].'Model';
					clearstatcache();
					includeCache($pto);
				}
				if(!fileExistsCase($to) || filemtime($src) > filemtime($to) ){
					$classContent=preg_replace('/class\s+(.+?)\s*{/i','class '.$className.'Model extends '.$driver.' {',$classContent,1);
					//编译插件
					$classContent = preg_replace_callback('#\t*\/\/\s*hook\s+([^\s]+)#is', 'Candy\Core\Hook::processHookCallback', $classContent);
					//生成model
					filePutContents($to,$classContent);
				}
				$className = $className . 'Model';
			}else{
				if(!fileExistsCase($to)){
					Debug::showMessage($className . '的Model对象不存在请检查 ！', 'Mysql');
				}
			}
		}
		
		clearstatcache();
		includeCache($to);
		return $className;
	}
	
	
	/**
	 * 类名和目录
	 *
	 * @param	string	$className	类名
	 */ 
	public static function getClassInfo(string $className,bool $isAddon,string $appName = ''): array
	{		
		empty($appName) && $appName = C('APPNAME');
		$appName = C('LAPPNAME') ?: '';
		$controlerpath = RUNTIME .'Controls/' . ($isAddon ? 'Addons/' : '') . preg_replace("/[\/\\\\]{1,}/", '/', $appName);
		$info = self::getExtendInfo($className,$isAddon, $controlerpath, $appName);
		
		$extendClassName = '';
		$className = str_replace('/', "\\", $className);
		if(!empty($info)){
			//加载语言
			$langfile = $info['path'] .'/Languages/'. G('LANG') .'/'. preg_replace("/[\/\\\\]{1,}/", '/', $appName) . '/' . $className.'.lang.php';
			if(fileExistsCase($langfile)){
				include($langfile);
				$GLOBALS['LANG'] = array_merge($GLOBALS['LANG'], $LANG);
			}
			
			//判断是否为Addon
			if($isAddon){
				if($info['extend']){
					$extendClassName = 'Extend\\Addon\\'. $appName . '\\' . $className .'Action';
				}
				$className = 'APP\\Addon\\'. $appName . '\\' . $className .'Action';
			}else{
				if($info['extend']){
					$extendClassName = 'Extend\\Control\\'. $appName . '\\' . $className .'Action';
				}
				$className = 'APP\\Control\\'. $appName . '\\' . $className .'Action';
			}
		}else{
			//判断是否为Addon
			if($isAddon){
				$className = 'APP\\Addon\\'. $appName . '\\' . $className .'Action';
			}else{
				$className = 'APP\\Control\\'. $appName . '\\' . $className .'Action';
			}
		}
		
		return ['className'=>$className,'extendName'=>$extendClassName,'path'=>$controlerpath,'extend'=>$info];
	}
	
	/**
	 * 获取扩展信息
	 *
	 * @param	string	$className	类名
	 */ 
	private static function getExtendInfo(string $className,bool $isAddon,string $controlerpath,string $appName = ''): array
	{
		empty($appName) && $appName = C('APPNAME');
		empty($controlerpath) && $controlerpath = RUNTIME .'Controls/' . ($isAddon ? 'Addons/'. $appName : C('TMPPATH'));
		if(is_null(C('extendpath.' . C('RAPPNAME') . $className))){
			//强制目录
			$dir = $appName;
			$path = PLUGPATH . C('RAPPNAME') . '/Controls/' . $className . '.class.php';
			//其他应用目录
			if(!fileExistsCase($path)){
				$path = '';
				$inc = INCPATH.'Plug.inc.php';
				if(is_file($inc)){
					$config = include($inc);
					$list = $config['PLUG_LIST'];
					foreach($list as $name=>$conf){
						if(fileExistsCase(PLUGPATH . $name . '/Controls/' . $appName . '/' . $className . '.class.php')){
							$dir = $name;
							$path = PLUGPATH . $name . '/Controls/'. $appName . '/' . $className . '.class.php';
							break;
						}
					}
				}
			}
			
			if(!empty($path)){
				$content = fileGetContents($path);
				$super='/extends\s+(.+?)\s*{/i'; 
				//如果已经有父类
				if(preg_match($super,$content, $arr)){
					$content=preg_replace('/class\s+(.+?)\s+extends\s+(.+?)\s*{/i','class \1Action extends \2 {',$content,1);
					$controlerfile = $controlerpath.'/'.strtolower($className).'action.class.php';
					$extend = false;
				}else{
					//扩展本身类库
					$content=preg_replace('/class\s+(.+?)\s*{/i','class \1Action extends \\APP\\Control\\'. $appName . '\\' . $className .'Action {',$content,1);
					$controlerfile = $controlerpath.'/'.strtolower($className).'action.extend.class.php';
					$extend = true;
				}
				
				//编译插件
				$content = preg_replace_callback('#\t*\/\/\s*hook\s+([^\s]+)#is', 'Candy\Core\Hook::processHookCallback', $content);
				//新生成控制器类
				filePutContents($controlerfile, $content);
				clearstatcache();
				
				C('extendpath.' . C('RAPPNAME') . $className, ['path'=>PLUGPATH . $dir, 'extend'=>$extend]);
			}else{
				C('extendpath.' . C('RAPPNAME') . $className, []);
			}
		}
		
		return C('extendpath.' . C('RAPPNAME') . $className);
	}
	
    /**
     * 获取应用根目录
     * @access public
     * @return string
     */
    public function getRootPath(): string
    {
        return CANDYROOT;
    }

    /**
     * 获取应用基础目录
     * @access public
     * @return string
     */
    public function getBasePath(): string
    {
        return CANDYROOT . 'Application' . DS;
    }
}
